Apple Location Manager
SDK 2.0.1

January 9, 1998

 

 

By Erik Sea - © 1996-1998, Apple Computer Inc.

 

This document is designed to be viewed in the web browser of your choice.

Visit the ALM Developer page on DevWorld!

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


Contents

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


What's New - Quick guide to changes between 1.0.x & 2.0.1 of ALM

This section is summarizes the differences between ALM 2.0.1 and its predecessors; if you have not worked with ALM before, you should skip to the Summary section.

Note: there was an ALM 2.0 previously distributed with this SDK, but that version has been withdrawn due to a problem on 68K machines that has been fixed in 2.0.1

ALM 2.0.1 is enabled on desktops!

You asked via email. You asked over the phone. You asked at WWDC and other conferences. You posted hacks around the restriction on comp.sys.mac.portables. We heard. ALM 2.0.1 runs happily on desktops or PowerBooks (1.0.x only ran on PowerBooks), and is scheduled to be available to everyone as of an upcoming system release. We thank you for your support!

ALM 2.0.1 is easier to use!

In ALM 1.0.x, the user was faced with a window in which locations were listed, and a separate window in which settings were added to locations by clicking on a button to move them from the left to the right (MacWeek described this as somewhat too much like Font/DA mover, for those who remember System 6). In 2.0.1, there is one window, and settings are "on" or "off" via a checkbox, rather than moving from one list to another; this does mean that, if order is important, the user will have to move settings around, but it turns out that it almost never is important.

In addition, the EditSetting call, which was not used extensively in ALM 1.0.x, is fully-implemented in ALM 2.0.1, and module developers are strongly encouraged to support it so as to facilitate editing non-active settings for non-current locations.

Specific Details

Enough with the hype. A lot of the changes are generic stability-enhancements and bug fixes that I won't bore you with. Here are some of the details:

New API Calls

There are now calls for creating locations, merging settings into existing locations, and selecting locations, all with a normalized API. See ALMPutLocation, ALMMergeLocation, and ALMGetLocation for details. (the bit on gestaltALMAttr is gestaltALMHasSFLocation)

New File Types

ALM 1.0.x modules all have a file type of 'thng'. These files will continue to work with ALM 2.0.1, however, we now distinguish between "action" modules (which have a file type of 'almb') and "state" modules (which have a file type of 'almn'). Action modules did exist under ALM 1.0.x (the Auto-Open Item module was one), but the means for specifying an action module were never documented. Now they are. In addition, a future version of the Finder will be able to automatically route 'almb' and 'almn' files to the modules folder, whereas 'thng' module files will never be routed correctly (there are other 'thng' files that want to go to other places).

Additional Events

Since there have always been API calls that enable developers to build their own list of locations, ALM 2.0.1 send notifications to registered clients when the locations list has been changed (a location has been deleted, renamed, or created by the user). (the bit on gestaltALMAttr is gestaltALMHasRescanNotifiers)

Switch Escalation

A module can now decide what it's going to do based on what modules before it have done.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


Summary of "What ALM is"

The Apple Location Manager (ALM), version 1.0, was announced at MacWorld Expo in San Francisco on January 6, 1997 (see link at bottom for full text):

...

Apple Computer, Inc. today announced a free software utility for PowerBook computers called Apple Location Manager. Apple Location Manager software makes it easy for PowerBook users to move from one location to another without having to spend a lot of time manually reconfiguring their computer with every move.

"Mobile users, by definition, change location frequently. Apple Location Manager takes the difficulty out of moving from one place to another because with a single command, a user can reconfigure his or her system to the settings needed at any given location," said Dale Fuller, vice president and general manager for the PowerBook division. "It's a small piece of software, but it does a big job and saves people a lot of time and inconvenience. It's what Apple is all about...making complex tasks simple."

...

http://product.info.apple.com/pr/press.releases/1997/q2/970106.pr.rel.locmgr.html

As you may gather from the above excerpt, ALM provides a user interface for saving and restoring sets of settings so that PowerBook users can reconfigure their systems easily as they move from place to place. As of ALM 2.0.1, desktop users can maintain their systems in similar fashion (whether they carry them around or not).

Although ALM ships with support for switching the default printer, TCP/IP settings, time zone, and a few other things, the ALM software is primarily an infrastructure for storing, retrieving, and applying sets of settings, and we expect third-party developers who are interested in meeting the needs of mobile users will be eager to use this framework to enhance their products, so we are providing this SDK.

Supporting ALM is not difficult - most of the time, you will not need to modify your product at all to add ALM support.

For most developers, "supporting" ALM means simply that - providing ALM with enough information to switch settings under user control in a way that is compatible with software that uses those settings. In addition to providing the infrastructure for making these changes, however, ALM also provides an API that developers can use to do a number of other things: applications can initiate switches, can request notification of switches while they are running, and can get information about user-defined sets of settings. These calls allow developer applications to become "location-aware" or they might be used to create "location-sensing" applications that could initiate switches automatically based on changes in the machine's environment. In ALM 2.0.1, applications can use API calls to create locations in order to help the user aggregate groups of settings.

Availability

Version 1.0.2 of ALM is available as part of Mac OS 8. Version 2.0.1 of ALM is scheduled to be part of Mac OS 8.1.

Acknowledgements

Many thanks to the entire ALM team for their tireless efforts in getting ALM into the hands of users and developers. Our collective thanks are also extended to third-party developers who participated in the seed program, without whose feedback and support ALM wouldn't be as useful nor as reliable as it is, and still further thanks for input to the many developers who have emailed, called, and cornered me at developers functions.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


Definitions

Action Module - A module that doesn't directly apply changes to machine state; the module "Auto-Open Items" is such a module.

ALM - Apple Location Manager.

Apple Location Manager - software suite composed of (at least) three pieces: a System Extension providing the system software infrastructure to switch between locations; a Control Panel providing the user interface for defining settings associated with a location and allowing users to switch between locations; a Control Strip Module to allow the user to switch between locations easily.

Current Location - the last location switched to. A special state called "None (off)" (not considered to be a Location) signifies that ALM has been turned off.

Deferred Switch - where a switch is initiated by the user at boot, if not all module settings in the location support switching at boot time, the switch will be reattempted when the Finder is running.

Depth - amount of information a module stores; for example, the Extensions Manager module only stores the name of an extension set, since that allows the user to redefine the extension set without adjusting every module that uses it; the Generic module, on the other hand, stores everything about a specified preference file, which may not be desirable. Basically, if a piece of software supports some concept of "named sets" within itself, a module should go no deeper than that set name, but, if a preference format is "universal", the module should capture everything as a setting.

Edit Location - the location that the user is currently configuring. This may not be the current location, and well-written modules allow the user to edit the values of settings that are not currently active.

Export - an ALM and module function that allows the user to capture enough information to take a setting to another machine and use it (provided the other machine has the same software and modules installed). Modules that support export may need to gather additional information to enable the importer to be able to recreate the setting.

Foot - thing at the end of a leg; also the symbol for ALM (see also Walkabout); often mistaken for a Paramecium.

Import - take a location exported by ALM and make it available for use on this computer.

Location - any positive number of settings, given a name by the user.

Module - a piece of code that interfaces with the ALM application and provides several functions that ALM uses to capture and apply a setting; a given module might or might not have settings associated with a given location.

Paramecium - a tiny, single-celled creature thought to resemble a stylized human foot (or maybe a slipper).

Reboot flags - depending on what a module changes, it may require the machine to reboot, or it may not; these flags are set by a module to specify its requirements that can then be communicated to the user when a switch occurs.

Setting - variable-length information owned by a module, returned to and preserved by ALM, then sent by ALM back to a module to effect a location switch.

State Module - a module that effects changes to the state of the settings or preferences on the system; the "File Sharing State" module is such a module.

Switch - an event (normally driven by the user), during which the current location changes; all modules associated with the "switched-to" location are asked to apply the settings they had previously defined for that location.

Task - old, pre-1.0 name for a Module.

Walkabout - old name for ALM, more obviously associated with feet.

Widget - old, pre-1.0 name for a Module.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


Installing and Using ALM

Installation

Provided with this SDK are GM versions of ALM 1.0.2 and 2.0.1 for your use in testing and development. Recall that while ALM 1.0.2 will install on non-PowerBooks, it will not run on them. This distribution does not include a debug build of ALM. ALM 1.0.1 was never released publicly.

What goes where

Although using the installer is recommended, you may be interested in knowing where various pieces are placed, so here is a list of the pieces in the 1.0.2 install:

:System Folder:Control Panels:Location Manager
:System Folder:Control Strip Modules:Location Manager
:System Folder:Extensions:Location Manager Extension
:System Folder:Extensions:Location Manager Guide Addtns
:System Folder:Extensions:Location Manager Modules:Auto-Open Item
:System Folder:Extensions:Location Manager Modules:Default Printer
:System Folder:Extensions:Location Manager Modules:Extensions Mgr
:System Folder:Extensions:Location Manager Modules:File Sharing
:System Folder:Extensions:Location Manager Modules:Network
:System Folder:Extensions:Location Manager Modules:Sound
:System Folder:Extensions:Location Manager Modules:TimeZone
:System Folder:Preferences:Location Manager Prefs:Locations:Sample

Similarly, under ALM 2.0.1, the chunks are:

:System Folder:Control Panels:Location Manager
:System Folder:Control Strip Modules:Location Manager Controls
:System Folder:Extensions:Location Manager Extension
:System Folder:Extensions:Location Manager Guide Addtns
:System Folder:Extensions:Location Manager Modules:AppleTalk &TCP/IP
:System Folder:Extensions:Location Manager Modules:Auto-Open Item
:System Folder:Extensions:Location Manager Modules:Default Printer
:System Folder:Extensions:Location Manager Modules:Extension Set
:System Folder:Extensions:Location Manager Modules:File Sharing State
:System Folder:Extensions:Location Manager Modules:Internet Access
:System Folder:Extensions:Location Manager Modules:Remote Access
:System Folder:Extensions:Location Manager Modules:Sound Level
:System Folder:Extensions:Location Manager Modules:Time Zone

These are, of course, localized for different countries.

Using ALM

Once you have installed and restarted, open the control panel and play with some settings. ALM has comprehensive Balloon Help and Apple Guide support for your reference; most users catch on fairly quickly.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


The Generic Module: Play with a Typical Implementation

If you want to get a feel for how modules work, the SDK provides a sample module, which is compiled to "Generic" and can be used to create a custom module quickly for experimental purposes. We do not, however, recommend that you use this technique to create a "finished" module, particularly since the Generic module has not been heavily tested by any stretch of the imagination!

That said, a lot of what modules do is similar. The Generic module provided with this SDK can be quickly customized with your favorite resource editor to provide a working module for a wide range of software, under the assumption that the software maintains a preference file in its preferences folder. With these instructions, you could create a working module for software that follows the "preference file" model in about 10 minutes.

Before I describe the "customization", however, be aware that, as with most generic solutions, a module derived from Generic without material code changes is not going to be terribly efficient, both in speed and in memory use, and should not be considered the "preferred" means for supporting ALM. I encourage you to plan and design your own module, perhaps by modifying the Generic code itself.

With that said, also be aware that these instructions are "quick & dirty" - very little in the way of explanation is provided. So, make a copy of the Generic module, giving it an appropriate name. The Generic module is set up to store preferences for MicroSoft Word 5, and, although it is in a "working" state, there are some things that need to be tidied up, so if you'll go through that exercise, you'll have a good idea of how to customize the module for your own use.

    So, you can see how easy it is to customize a module for use in many cases. The next section describes how to actually code a module, either from scratch or using the Generic module's code as a starting point.

    The complexity of writing a module will, of course, vary with the complexity of the software with which the module will interact. As a general rule, however, writing an ALM module is about half the complexity of writing a Control Strip module to perform the same function, but is more complex than buttering toast.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


Module Needs: What Modules Must Do

Now that you've seen what you can do just by modifying the compiled Generic module, I hope you'll consider implementing your own module by modifying the Sample code, which is only slightly more involved (you still believe me, don't you?).

Headers & Environments

The ALM headers have been distributed with CodeWarrior Pro 2 and in the Universal Interfaces 3.0.1. This SDK no longer includes its own versions of the headers. Also, if you plan to use a development environment other than the most current MPW or CodeWarrior, you're on your own.

Debugging Modules

In ALM 2.0.1, once a module's signature is known, you can replace the module as often as you wish; there will be a brief pause while ALM rescans the modules folder, but, other than that, you only need to restart the first time you install your module.

Component Technology

The Component Manager is documented extensively in Inside Macintosh: More Macintosh Toolbox, and much of the discussion there I will either assume or ignore. See also the discussion of the 'thng' resource in the earlier section. Only three items are defined in the Rez header "LocationManager.r". The component type is kALMComponentType ('walk' for those who prefer graphical resource creation). The only other field of interest in the 'thng' resource are the "manufacturer flags", two of which are currently used in ALM:

#define   kALMMultiplePerLocation     1 /* bit 0 */
#define   kALMDescriptionGetsStale    2 /* bit 1 */

Bit kALMMultiplePerLocation indicates that multiple instances of this module can be added to a location; this is how the Auto-Open Item is defined.

Bit kALMDescriptionGetsStale causes ALM to "re-query" a module, to get new descriptions more frequently. Usually, if the settings have not changed, ALM assumes the description has not changed either, but this may not be the case in some modules; for example, the Extensions Manager module is intelligent enough to report that the current extensions set has not changed if the user simply renamed it - the description would refer to the old name if this bit were not set.

All other bits are reserved.

One thing about the Component Manager I will reiterate here is that it is based on "single code resource" technology, and, as such there is one entry point, and the call type is specified by a selector. Negative selectors are defined by the Component Manager, and are used for component "Open" and "Close" calls, among others (see the sample code). Nonnegative selectors correspond to the ALM module API:

kALMGetCurrentSelect
kALMSetCurrentSelect
kALMCompareSettingSelect
kALMEditSettingSelect
kALMDescribeSettingSelect
kALMDescribeErrorSelect
kALMImportExportSelect
kALMGetScriptInfoSelect
kALMGetInfoSelect

Also, in ALM, the convention is to set the "doAutoVersion" bit in the 'thng' resource. Otherwise, duplicate versions of your module may confuse the user, and potentially ALM itself.

You should be aware that, in order to reduce memory footprint, ALM does not keep modules around long, so you can expect modules to be opened and closed frequently - try to keep your module fast. Also, it is generally considered to be bad form to fail in component Open routine, so I suggest you defer most of your initialization to the first "real" call. Remember, if there is a problem, you want to be able to explain it to the user if at all possible, and that requires your component to open successfully. One exception to this rule is if you know the user will never be able to use your module on the given machine; for example, an Infrared module Quadra 840av is probably never going to be useful, and the user probably doesn't expect it to be useful. In that case, it is entirely reasonable to fail in your open routine (though, because of a bug, it's still not recommended if you intend to support ALM 1.0.x).

Handling Global Data

ALM Component Manager-based calls come in two flavors: with global data passed as the first parameter, and without. The ALM header "LocationManager.k.h" provides a means for you do implement ALM calls either all one way, or all the other, using a combination of macros. Using these macros may help you transition your code if ALM were to be implemented using CFM. I recommend using the header in the following manner if you intend to pass global data using the Component Manager:

#define    ALM_BASENAME()
#define    ALM_GLOBALS()      Globals

#include   <LocationManager.k.h>

You would then define the Globals data type, and expect it as the first parameter to your routines. And if you don't want global data, simply remove the second line, that is:

#define    ALM_BASENAME()

#include   <LocationManager.k.h>

If you prefer to use "real" global data, you're on your own - consult the documentation for your development environment for ideas and strategies. The Generic module fiddles with A5-worlds, but only to initialize QuickDraw in order to (reliably) display its dialog box.

Options to Boot

Some modules require rebooting for the changes to take effect. To assess the impact of such changes, the module API lets ALM know if a reboot is required. If switching to a location involves a module requiring a reboot, ALM offers the user the chance to reboot, shutdown, or continue working after all modules are completed. There a number of options; for the most part, modules will return kALMNoChange (in the event the switch-to setting is the same as the current setting), kALMAvailableNow (in the event no rebooting is required), or kALMExtensions (in the event extensions need to be reloaded; this implies a restart in the current OS). In ALM 2.0.1, a module can make decisions based on what previous modules have done; for example, if an Extension Set has changed and requires a reboot, any module after the Extension Set could decide to defer its action until after the restart has occurred.

kALMNoChange
kALMAvailableNow
kALMFinderRestart
kALMProcesses
kALMExtensions
kALMWarmBoot
kALMColdBoot
kALMShutdown

The API Itself

This is the moment you've been waiting for - the definitions for each of the nine API calls a module may support (some are optional). In the following, I will assume you've followed the recommendation given above, and defined ALM_BASENAME() to nothing, so that these will be your routines, as prototyped for you in LocationManager.k.h (shown in both non-global and global format). While this summary may be good for reference, to get a feel for the calls I suggest you refer to the sample and explore its functionality.

GetCurrent

pascal ComponentResult GetCurrent (Handle setting);
pascal ComponentResult GetCurrent (Globals globals, Handle setting);

When this call is made, the setting will already be allocated (but not the right size), so resize it as necessary; the format of your data is entirely private to you, and ALM simple stores the entire handle, whatever its size. Cast it to your private setting handle type and fill it with information describing whatever preferences your module cares about.

Return an error if the software you need isn't installed, or if the current setting suggests that the software isn't initialized (the Time Zone module, for example, returns an error if the current location has not been set.)

As stated previously, modules should Open even when the software the module works with isn't installed. You can then return an error from GetCurrent to tell the user what's wrong with the system.

Try to keep the setting size to the minimum required to effect a SetCurrent call. For example, the Extension Set module stores little more than the name of the current Extensions Manager Set.

Action/State Module differences

An action module has not concept of "current" settings. Consider the case of the Auto-Open Items module: what is the "current" Auto-Open Items value in the system? Clearly, there is none. Nevertheless, an action module does need to support GetCurrent, but should return a settings value that can be identified as "incomplete" by other calls the module implements. ALM will call EditSetting immediately after GetCurrent with this "incomplete" setting.

SetCurrent

pascal ComponentResult SetCurrent (Handle setting, ALMRebootFlags* flags);
pascal ComponentResult SetCurrent (Globals globals, Handle setting,
                                       ALMRebootFlags* flags);

Set the current settings for your module; the setting passed in will be one previously returned to ALM on a GetCurrent call. Indicate via *flags what type of rebooting is necessary, if any. If you cannot complete your SetCurrent call (for example, because you are being called at INIT time), return kALMDeferSwitchErr and ALM will call you again at a "nicer" time.

Under ALM 2.0.1

The input value of *flags represents the current "escalation level" within a location switch; that is, the highest value set by previous modules. A module might use this information to change its behavior. For example, the Auto-Open Items module will defer opening items if any previous module has signaled a restart requirement (users would have to carefully position their Auto-Open Items setting at the end of their location to experience this benefit). If you cannot (or should not) set the current setting because of the escalation level, you can return kALMRebootFlagsLevelErr.

CompareSetting

pascal ComponentResult CompareSetting (Handle setting1, Handle setting2,
                                  Boolean* equal);
pascal ComponentResult CompareSetting (Globals globals, Handle setting1,
                                  Handle setting2, Boolean* equal);

Compare the contents of two settings. ALM uses this to determine if the setting your module is responsible for has changed and requires an update. Updates are currently only done by the user in the ALM Control Panel, but future versions may allow the user to update at other times when a change is detected.

Under ALM 2.0.1

CompareSetting may be called at switch or restart or shutdown time, if the user has selected the "update settings" option.

EditSetting

pascal ComponentResult EditSetting (Handle setting);
pascal ComponentResult EditSetting (Globals globals, Handle setting);

Interact with the user to modify the contents of the setting. Present whatever interface is necessary (launch your application, bring up your control panel, even show a movable modal in the ALM Control Panel's context). If you cause ALM to be put in the background, bring it to the foreground after the editing is done (this implies that you also need to know when editing is "done").

If the user cancels the edit, return userCanceledErr from the function.

This call is currently optional; the Component Manager's "canDo" selector is used to determine if the module supports it or not. Although this call is optional, if you do not implement it, the user will be required to edit "live" settings to make changes, and then use the ALM Control Panel to update the setting; the user may find this confusing. We strongly encourage you to implement this call; future versions of ALM may require it, and your module might be disabled if it does not support EditSetting.

Under ALM 2.0.1

The user can invoke your EditSetting call by clicking on the "Edit" button with your module hilited. If you don't implement EditSetting, the user gets a nasty "I don't know what to do with this module" dialog, which isn't the best user experience.

Action/State Module differences

Action modules must always implement the EditSetting call because there is no concept of "current settings" for an action module; see additional discussion under GetCurrent above.

DescribeSettings

pascal ComponentResult DescribeSetting (Handle setting, CharsHandle text);
pascal ComponentResult DescribeSetting (Globals globals, Handle setting,
                                  CharsHandle text);

Generate text which will be used in the location window to express what the setting represents. The description handle "text" will already be allocated. Resize it to fit the string you plan to return. The length of the text ALM displays is determined by the size of the description handle. The font information returned by GetScriptInfo will be used to display the text.

Under ALM 1.0.x

This routine was called "DescribeSettings". We apologize for our previously inconsistent use of the plural in our API. You can still use DescribeSettings if you define OLDROUTINENAMES to 1 in your compilation.

DescribeError

pascal ComponentResult DescribeError (OSErr lastErr, Str255 errStr);
pascal ComponentResult DescribeError (Globals globals, OSErr lastErr,
                                  Str255 errStr);

Generate a string which will be used in the location window (or the switch window) to describe an error. If you return paramErr, a generic routine will be used to describe the error. Make an attempt to describe the errors most likely to be returned by your various other routines. The technique Apple's modules use is to convert generic errors to specific ones; the Extension Set module might translate certain instances of fnfErr (-43) to a private, positive number, which this routine might describe as "The Extensions Manager is not installed."

ImportExport

pascal ComponentResult ImportExport (Boolean import, Handle setting,
                                  SInt16 resRefNum);
pascal ComponentResult ImportExport (Globals globals, Boolean import,
                                  Handle setting, SInt16 resRefNum);

This call is optional, and many modules do not need to implement it. However, consider the case of the Extension Set module: it stores the name of the current extensions set, but what does that mean on another machine? ImportExport to the rescue.

There are many strategies that you can use to manage the "duality" of settings that normally only need to store a little information when used on the same machine, but need to capture a lot of information if the setting is going to be moved to another machine.

If a module supports this call, it may be useful to define a field in the setting to indicate whether it is in exported or local form, assuming the data is all to be stored in the handle still.

If it is not convenient to have two forms of setting handle, you can call UseResFile (resRefNum), to set the resource fork to the current import/export file, and add additional data as resources (or remove them, in the import case). To avoid resource collisions, you use your module's component signature as a reserved resource type. Special strategies may be necessary if you add resources and your module allows itself to be added to a location multiple times.

GetScriptInfo

pascal ComponentResult GetScriptInfo (ALMScriptManagerInfo* info);
pascal ComponentResult GetScriptInfo (Globals globals,
                                  ALMScriptManagerInfo* info);

This call gets information from the module that will allow ALM to display the various strings the module returns in the correctly localized script and region. Return the fields in accordance with how your module has been localized.

#pragma options align=mac68k

typedef struct {

SInt16          version;
SInt16          scriptCode;
SInt16          regionCode;
SInt16          langCode;
SInt16          fontNum;
SInt16          fontSize;

} ALMScriptMgrInfo;

#pragma options align=reset

Although this call is optional, it is recommended that you implement it, along the style provided in the sample code: the headers even provide a conveniently localizable alternate form (the sample shows how to use it). If you do not implement it, ALM will assume the current environment, something like this:

version    = kALMScriptInfoVersion;
scriptCode = smSystemScript;
regionCode = GetScriptManagerVariable (smRegionCode);
langCode   = GetScriptVariable (smSystemScript,
                                  smScriptLang);
fontNum    = GetScriptVariable (smSystemScript,
                                  smScriptAppFond);
fontSize   = GetScriptVariable (smSystemScript,
                                  smScriptAppFondSize);

GetInfo

pascal ComponentResult GetInfo (CharsHandle* text, STHandle* style,
                                  ModalFilterUPP filter);
pascal ComponentResult GetInfo (Globals globals, CharsHandle* text,
                                  STHandle* style, ModalFilterUPP filter);

This call is made when the user clicks the "Get Info" button in the location editing window.

It can return a text handle (and an optional style handle), or it can do its own thing, such as launching an external help system or displaying its own dialog. The text, if returned, will be displayed in a scrolling window.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


API: Driving ALM from Applications

Although ALM is, by itself, a fairly comprehensive software suite, it was recognized early in the design that if the framework were exposed, third-party developers could exploit some of ALM's internal workings to create customized solutions that we hadn't thought of. Also, during the development of modules, some common tasks began to emerge that we think other module developers would prefer not to reimplement.

In this SDK, you will find the header "LocationManager.h", interface "LocationManager.p" and even "LocationManager.a", if you are so inclined. If your project is PowerPC-based, you will need to link with the stub library LocationManagerLib. Weak linking is recommended; compare one of the seven exported routines against kUnresolvedCFragSymbolAddress (before calling any of them) to see if ALM is installed. Note that although the stub library does contain CFM-68K stubs, ALM 1.0 as currently distributed, including with this SDK, does not contain the corresponding CFM-68K implementation. For this reason, I recommend classic 68K development for now.

AppleScript

Although this is mentioned in the user's Read Me, if you prefer to speak AppleScript, it is possible to change the current location thusly:

   tell application "Finder"
     open file ((control panels folder
as string) & "Location Manager")
   
  tell application "Location Manager"
   
    set current location to location myLocationName
   
  end tell
   
end tell

If that fails to amuse you, consider the script to return the name of the current location by:

   tell application "Finder"
     open file ((control panels folder
as string) & "Location Manager")
   
  tell application "Location Manager"
   
    set currLoc to current location
   
    set curLocName to name of currLoc
     end tell
   
end tell
   curLocName

If you see specific functionality that you think should be scripted, please send your feedback to DevSupport.

Determining what ALM features are available

As with most things Mac, you should use gestalt to check for ALM (you do not need to do this in a module, since modules will only be called if ALM is around anyway, so checking would be somewhat redundant). Two gestalt selectors are defined: gestaltALMVers which returns the version of ALM installed in NumVersion format for your interest (get the pieces using the union NumVersionVariant.whole), and gestaltALMAttr which returns the attributes of ALM; you should test bit gestaltALMPresent to see if ALM is installed; there are other bits for version-dependant features.

Managing Locations

Four routines are defined to let you examine the locations a user has defined.

pascal OSErr
ALMGetCurrentLocation (SInt16* index, ALMToken* token, ALMLocationName name);

Gets three values describing the current location. Pass NULL for any value you don't want. Index is zero-based; in ALM 1.0, there can be at most 16 locations, so *index will never be more than 15, but this may change in future releases. If there is no current location, the *index will be returned as kALMNoLocationIndex, *token will be kALMNoLocationToken, and the name will be "None (off)", as localized. An ALMToken is a private ALM data structure reference.

pascal OSErr
ALMGetIndLocation (SInt16 index, ALMToken
* token, ALMLocationName name);

Use this call to index through the defined locations, returning their tokens and names. Note that you can pass kALMNoLocationIndex to get the localized version of the "None (off)" state. This function will return paramErr if the index is out of range. Again, pass NULL for any value you don't want returned.

pascal OSErr
ALMCountLocations (SInt16
* locationCount);

Returns the number of locations defined.

pascal OSErr
ALMSwitchToLocation (ALMToken newLocation, ALMSwitchActionFlags switchFlags);

Initiates a location switch. The switchFlags parameter is a set of flags that control switching options. Use kALMDefaultSwitchFlags for a normal switch or kALMDontShowStatusWindow for a "quiet" switch that does not put up the dialog box (not recommended).

If you are not sure about the environment in which you will be switching (for example, you are inside a background process, or inside a process that doesn't respond well to having a dialog suddenly popup inside its context), add the flag kALMSignalViaAE and the switch will be deferred until the Finder (or the Location Manager Control Panel) is the current process. The flag is so-named because the context is guaranteed by sending an AppleEvent since the Finder won't process an AppleEvent while it is not the current process!

Under ALM 1.0.x, do not make this call at INIT time!

Creating/Naming/Getting Locations

These features are only available if the gestaltALMAttr bit number gestaltALMHasSFLocation is set (ALM 2.0.1). You may notice that these calls resemble the well-known Standard File package, and that is deserved - the filter and yourDataPtr parameters behave exactly as in the Standard File equivalents to these calls; to see them in action, you need only create or manipulate locations using the control panel.

pascal OSErr
ALMPutLocation (ConstStr255Param prompt, ALMLocationName name, SInt16 numTypes,
                      ConstALMModuleTypeListPtr typeList, ModalFilterYDUPP filter,
                      void* yourDataPtr);

The prompt appears above the dialog that is presented; the name is the default name on input (which the user may modify - the changed name is returned). The typeList is an array of module signatures, with numTypes indicating how many items are in the array, or, you may pass NULL for typeList, and kALMAddAllOff for numTypes to create an "empty" location. To create a location which uses all installed modules to capture the current system settings, pass kALMAddAllOnSimple for numTypes (action modules are not added to the location with this value). Returns userCanceledErr if the user dismisses the dialog.

pascal OSErr
ALMMergeLocation (ConstStr255Param prompt, ALMLocationName name, SInt16 numTypes,
                      ConstALMModuleTypeListPtr typeList, ModalFilterYDUPP filter,
                      void* yourDataPtr);

This behaves almost identically to ALMPutLocation, except that the user must choose an existing location. Any existing values in the location are replaced.

pascal OSErr
ALMGetLocation (ConstStr255Param prompt, ALMLocationName name,
                      ModalFilterYDUPP filter, void* yourDataPtr);

Provided for completeness; prompts the user to choose a location, returning the name of that location.

Detecting Switches & Changes in the Locations list

ALM sends events to all AE-aware applications currently running whenever a switch occurs. The event has an AEEventClass of kAECoreSuite and an AEEventID of kAESystemConfigNotice. If event contains a parameter keyed under kAELocationChangedNoticeKey, treat the data as a 32-bit quantity representing an ALMToken of the location to which the user just switched.

Under ALM 2.0.1, if bit number gestaltALMHasRescanNotifiers is returned on from gestaltALMAttr, you will also receive (with the same class and ID) events when the user renames, creates, or deletes locations, but there will be a parameter keyed under kAELocationRescanNoticeKey instead. The value of the key is also a 32-bit ALMToken, of the current location.

As always, any events you receive that do not have parameters you recognize should be ignored.

If you are not an application (no, not you personally, but surely you view yourself as your code, right?), you can use the following routines to register a callback routine for notification:

pascal OSErr
ALMRegisterNotifyProc (ALMNotificationUPP notificationProc,
                    const ProcessSerialNumber
* whichPSN);

pascal OSErr
ALMRemoveNotifyProc (ALMNotificationUPP notificationProc,
                    const ProcessSerialNumber
* whichPSN);

You create an ALMNotificationUPP using the conventional myRoutineUPP = NewALMNotificationProc (MyALMNotificationRoutine), and dispose of it with DisposeRoutineDescriptor (myRoutineUPP). Your routine should conform to this interface:

pascal void
MyALMNotificationRoutine (AppleEvent
* theEvent);

Extract kAELocationNotice from theEvent in the same fashion as you would in an AEHandler.

This just in

It has been discovered that AppleEvents are not always sent; if you are having problems in you application with receive AppleEvents from ALM, be aware that you can still the routines ALMRegisterNotifyProc and ALMRemoveNotifyProc from an application.

Module Import Collisions

As discussed earlier, where preferences supported by a module keep track of named configurations, such as under Open Transport or Extensions Manager, the module should only keep track of the name of that configuration, until it needs to do an export. The problem becomes, then, that an Importing user might have a setting with the same name that is not the same setting. Obviously, it would not be good to blindly overwrite the existing setting. So, ALM provides the above call so that a module may prompt the user, without going through the general hassle of setting up a user interface within a code resource, for a new name (or to replace the old name).

pascal OSErr
ALMConfirmName (ConstStr255Param msg, Str255 configName,
                    SInt16* choice, ModalFilterUPP filter);

Typically, the module developer will call this routine with msg as a message indicating the conflict occurred. If a ^0 is embedded within the string, it will be replaced with the configName parameter for presentation to the user in the dialog (for example, if msg is "The config named "^0" exists." and configName is "MyConfig", the user sees a dialog with "The config named "MyConfig" exists."). If the user chooses to rename the config, the new name is returned in configName, and *choice is set to ALMConfirmRenameConfig; you should then check to see that the user hasn't collided with yet another config, possibly making this call again. If the user chooses to replace the config, you will get *choice of ALMConfirmReplaceConfig. The only other possibility is that the user cancels the whole operation, in which case the function returns userCanceledErr and *choice is not defined.

The final parameter, filter, is a standard dialog filter that you can use to filter events; set it to NULL otherwise. In ALM 1.0.x, the filter function is only called while the second dialog is up. This is a bug; future versions will call your filter function during both dialogs' tenure. If the refcon of the dialog is zero, you can presume you are being called from ALM 1.0.x. Under ALM 2.0.1, the duplicate dialog has a refcon of kALMDuplicateDialogRefCon, while the rename dialog has a refcon of kALMRenameDialogRefCon.

Additionally, to assist you in writing your filter, the dialog item numbers are provided for your use; see the interface file.

Errors

Listed here for completeness; most of these are unremarkable, although recall that a module that cannot switch at startup time should return kALMDeferSwitchErr if it cannot handle a SetCurrent call at boot time. Generally, modules should only return errors that can be translated into informative messages to users via the DescribeError call.

kALMInternalErr              = -30049
kALMLocationNotFoundErr      = -30048
kALMNoSuchModuleErr          = -30047
kALMModuleCommunicationErr   = -30046
kALMDuplicateModuleErr       = -30045
kALMInstallationErr          = -30044
kALMDeferSwitchErr           = -30043
kALMRebootFlagsLevelErr      = -30042

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


Future Directions

Shared Library Model

ALM has a long genesis, and currently uses the Component Manager to implement modules. A future version of ALM is likely to support CFM, but Component Manager modules will probably continue to be supported simultaneously for a period of time to protect users' investment in your software.

Beyond 2.0.1

As this is written, ALM 2.0.1 is just out the door, and, although we already have a "wish list" for future versions, it would be premature to comment on the possibilities right now.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources


Other Resources

Web

We try to maintain a website on DevWorld.

Reporting Bugs and Requests

If you find a problem or have a suggestion to make with respect to ALM or the SDK, please submit your report to DevSupport.

Reference Material

"Preferential Treatment Under Apple Location Manager", an article that covers the ALM API in depth, including 2.0.1-specific features, in MacTech magazine, September 1997.

Techniques for Writing and Debugging Components, develop 12.

Component Manager, Inside Macintosh: More Macintosh Toolbox.

Go to: Top - What's New - Summary - Definitions - Installing- Generic - Module Needs - API - Future - Resources